<HTML><HEAD><TITLE>/home/steder/Projects/Tutorials/python/BobChat-v0.3/BobClient.py</TITLE></HEAD>
                  <BODY BGCOLOR=#FFFFFF>
                  <!--header-->
                  <!--script--><PRE><FONT COLOR=#115511>"""
Protocol.py
---
Defines the BobChat Protocol:
Message Objects,
Protocol Constants,
Commands.
"""</FONT>

<FONT COLOR=#3333CC><B>import</B></FONT> string <FONT COLOR=#1111CC># we do a lot of string processing</FONT>

<FONT COLOR=#115511>"""
Protocol Constants
"""</FONT>

<FONT COLOR=#115511>"""
Command List
"""</FONT>
COMMANDS = {<FONT COLOR=#115511>"QUIT"</FONT>:<FONT COLOR=#115511>"\QUIT password"</FONT>+
            <FONT COLOR=#115511>"Kill the server, disconnect everyone, and shutdown."</FONT>,
            <FONT COLOR=#115511>"EXIT"</FONT>:<FONT COLOR=#115511>"\EXIT"</FONT>+
            <FONT COLOR=#115511>"Inform all you're quitting the chat, then quit."</FONT>,
            <FONT COLOR=#1111CC># Everything below here needs additional server support.</FONT>
            <FONT COLOR=#1111CC># Conspire would maybe be better then whisper</FONT>
            <FONT COLOR=#115511>"STAB"</FONT>:<FONT COLOR=#115511>"\STAB username"</FONT>+
            <FONT COLOR=#115511>"Kick a user out of the Chatroom."</FONT>,
            <FONT COLOR=#115511>"WHISPER"</FONT>:<FONT COLOR=#115511>"\WHISPER username message"</FONT>+ 
            <FONT COLOR=#115511>"Send a private message to the specified user."</FONT>,
            <FONT COLOR=#115511>"JOIN"</FONT>:<FONT COLOR=#115511>"\JOIN"</FONT>+ <FONT COLOR=#1111CC># this needs to be automated</FONT>
            <FONT COLOR=#115511>"Politely Join the Chat"</FONT>,
            <FONT COLOR=#115511>"NICK"</FONT>:<FONT COLOR=#115511>"\NICK newname"</FONT>+ 
            <FONT COLOR=#115511>"Change your Nickname/Username"</FONT>,
            <FONT COLOR=#115511>"EMOTE"</FONT>:<FONT COLOR=#115511>"This one is for Rob Jacob"</FONT>,
            <FONT COLOR=#1111CC># Be careful of these two commands.</FONT>
            <FONT COLOR=#1111CC># They should not be used by clients</FONT>
            <FONT COLOR=#1111CC># except in making their initial connections.</FONT>
            <FONT COLOR=#115511>"_WRITE_"</FONT>:<FONT COLOR=#115511>"Internal Command, setup Write Socket"</FONT>,
            <FONT COLOR=#115511>"_READ_"</FONT>:<FONT COLOR=#115511>"Internal Command, setup Read Socket"</FONT>}

COMMANDLIST = COMMANDS.keys()
MESSAGETYPES=[<FONT COLOR=#115511>'Message'</FONT>,<FONT COLOR=#115511>'Command'</FONT>,<FONT COLOR=#115511>'ServerCommand'</FONT>,<FONT COLOR=#115511>'AdminCommands'</FONT>]

<FONT COLOR=#115511>"""
Bob Message Objects
"""</FONT>
<FONT COLOR=#3333CC><B>class</B></FONT><A NAME="Message"><FONT COLOR=#CC0000><B> Message</B></FONT></A>:
    <FONT COLOR=#115511>"""
    Message( username, message[, command, password] )

    Examples of Usage:
    1).  msg = Message('steder', 'Hey Phil, how's it going?')
      This creates a message in this format and sends it to the
      server, which timestamps it and returns it to all clients.
      It is then interpreted by the read client process into:
      'steder(4:03:21pm):  Hey Phil, how\'s it going?'
    2).  cmd = Message('steder', 'I'm out of here, bis spater!', '&lt;EXIT&gt;')
      This creates a message like the above command, the message is
      simply printed as a comment.  It's really just a placeholder
      for the executed command.  In this case, &lt;EXIT&gt; is just an example
      (I'm not settled on a command syntax yet), but intuitively
      this is the command a client sends when it wishes to disconnect
      from the chat.
      So the message object arrives at the server, and the &lt;EXIT&gt;
      is interpreted, which generates a message in this way:
      a).  Lookup command('&lt;EXIT&gt;')
      b).  'User '+username+' has left, saying:'+message
        'User steder has left, saying: I'm out of here, bis spater!'
    3).  servercommand = Message('root','Server is going down for maintenance',
    '&lt;QUIT&gt;','2l33t')
      OR
      bootmsg = Message('moderator', 'Die annoying guy!', '&lt;KICK&gt;AnnoyingGuy&lt;/KICK&gt;', 'r0xx0r')
    """</FONT>
    MESSAGETYPES=[<FONT COLOR=#115511>'Message'</FONT>,<FONT COLOR=#115511>'Command'</FONT>,<FONT COLOR=#115511>'ServerCommand'</FONT>]
    <FONT COLOR=#3333CC><B>def</B></FONT><A NAME="__init__"><FONT COLOR=#CC0000><B> __init__</B></FONT></A>(self, username, message, command=None, password=None):
        self.username = username
        self.message = message
        self.command = command
        self.password = password
        <FONT COLOR=#3333CC><B>if</B></FONT> command != None <FONT COLOR=#3333CC><B>and</B></FONT> password != None:
            <FONT COLOR=#1111CC># Server Command</FONT>
            self.type = 2
        <FONT COLOR=#3333CC><B>elif</B></FONT> command != None:
            <FONT COLOR=#1111CC># Client Command</FONT>
            self.type = 1
        <FONT COLOR=#3333CC><B>else</B></FONT>:
            <FONT COLOR=#1111CC># Message</FONT>
            self.type = 0
        <FONT COLOR=#1111CC># A timestamp variable.</FONT>
        <FONT COLOR=#1111CC># All messages are touched by the server,</FONT>
        <FONT COLOR=#1111CC># which places a timestamp on them.</FONT>
        self.time = <FONT COLOR=#115511>""</FONT>
        <FONT COLOR=#3333CC><B>return</B></FONT>
    <FONT COLOR=#115511>"""
    The server calls this function to set the time stamp on
    each message as it arrives.  More sophisticated versions
    of this program my encrypt some sort of secure key or something
    to 'sign' each message.
    """</FONT>
    <FONT COLOR=#3333CC><B>def</B></FONT><A NAME="approve"><FONT COLOR=#CC0000><B> approve</B></FONT></A>(self,time):
        self.time = time
        <FONT COLOR=#3333CC><B>return</B></FONT>

    <FONT COLOR=#115511>"""
    Returns the Typecode of a message object.
    Type 2 Messages are Server Commands, and need to be handled there
    
    Type 1 Messages are Client Commands, and are generally ignored by
    The server and dealt with by the client.  Usually these are just
    things like emote that require special formatting.

    Type 0 Messages are just plain simple messages.

    ADDITION:  Type 3 Messages should be added (or these should be Type 2)
    and Type 2 Server Commands should be called Type 3.
    We need a new type of message for things like private messages
    (if we want to implement them.)
    """</FONT>
    <FONT COLOR=#3333CC><B>def</B></FONT><A NAME="type"><FONT COLOR=#CC0000><B> type</B></FONT></A>(self):
        <FONT COLOR=#3333CC><B>return</B></FONT> MESSAGETYPES[self.type]

    <FONT COLOR=#115511>"""
    Designed to allow the following user/Client code:
      input = 'Hello Friend!'
      input2 = '\stab friendlyuser'
      message = Protocol.Message('friendlyuser',input)
      message2 = Protocol.Message('meanuser', input2)
      if message.isCommand():
          message.makeCommand()
      if message2.isCommand():
          message.makeCommand()
    """</FONT>
    <FONT COLOR=#3333CC><B>def</B></FONT><A NAME="isCommand"><FONT COLOR=#CC0000><B> isCommand</B></FONT></A>(self):
        <FONT COLOR=#1111CC># Standardize the message</FONT>
        message = self.message.upper()
        <FONT COLOR=#1111CC># Check for command tags at the beginning of the message.</FONT>
        temp = message.split()
        <FONT COLOR=#3333CC><B>for</B></FONT> command <FONT COLOR=#3333CC><B>in</B></FONT> COMMANDLIST:
            <FONT COLOR=#3333CC><B>if</B></FONT> temp[0] == <FONT COLOR=#115511>"\\"</FONT>+command:
                <FONT COLOR=#3333CC><B>return</B></FONT> self.write_handle( command, len(temp) )
        <FONT COLOR=#3333CC><B>return</B></FONT> 0

    <FONT COLOR=#115511>"""
    write_handle(self, commandlist, length):

    Verifys the command is syntactically correct
    then calls pack to get it ready to send.
    """</FONT>
    <FONT COLOR=#3333CC><B>def</B></FONT><A NAME="write_handle"><FONT COLOR=#CC0000><B> write_handle</B></FONT></A>(self, command, length):
        <FONT COLOR=#115511>"""
        _WRITE_ and _READ_ are commented out to
        prevent users from sending these commands.
        I just build these manually in the client code.
        """</FONT>
        commandlist = self.message.split()
        <FONT COLOR=#3333CC><B>if</B></FONT> command == <FONT COLOR=#115511>"_WRITE_"</FONT>:
            <FONT COLOR=#1111CC>#self.message = "Connecting Client _WRITE_ Thread"</FONT>
            <FONT COLOR=#1111CC>#self.command = "&lt;_WRITE_&gt;"</FONT>
            <FONT COLOR=#1111CC>#self.password = None</FONT>
            <FONT COLOR=#1111CC>#self.type = 2 # Server Commands that aren't protected</FONT>
            <FONT COLOR=#3333CC><B>return</B></FONT> 1
        <FONT COLOR=#3333CC><B>elif</B></FONT> command == <FONT COLOR=#115511>"_READ_"</FONT>:
            <FONT COLOR=#1111CC>#self.message = "Connecting Client _READ_ Thread"</FONT>
            <FONT COLOR=#1111CC>#self.command = "&lt;_READ_&gt;"</FONT>
            <FONT COLOR=#1111CC>#self.password = None</FONT>
            <FONT COLOR=#1111CC>#self.type = 2 # Server Commands that aren't protected</FONT>
            <FONT COLOR=#3333CC><B>return</B></FONT> 1
        <FONT COLOR=#3333CC><B>elif</B></FONT> command == <FONT COLOR=#115511>"QUIT"</FONT>:
            <FONT COLOR=#3333CC><B>if</B></FONT> length &gt;= 3:
                self.message = string.join(commandlist[2:],<FONT COLOR=#115511>" "</FONT>)
                self.command = command
                self.password = commandlist[1]
                self.type = 3 <FONT COLOR=#1111CC># Password protected server command</FONT>
                <FONT COLOR=#3333CC><B>return</B></FONT> 1
            <FONT COLOR=#3333CC><B>elif</B></FONT> length == 2:
                self.message = <FONT COLOR=#115511>"Admin is bringing the server down."</FONT>
                self.command = command
                self.password = commandlist[1]
                self.type = 3
                <FONT COLOR=#3333CC><B>return</B></FONT> 1
            <FONT COLOR=#3333CC><B>else</B></FONT>:
                <FONT COLOR=#3333CC><B>return</B></FONT> 0
        <FONT COLOR=#3333CC><B>elif</B></FONT> command == <FONT COLOR=#115511>"JOIN"</FONT>:
            <FONT COLOR=#3333CC><B>if</B></FONT> length &gt;= 2:
                self.message = <FONT COLOR=#115511>"&lt; "</FONT>+self.username+<FONT COLOR=#115511>": "</FONT>+\
                               string.join(commandlist[1:],<FONT COLOR=#115511>" "</FONT>)
                self.command = command
                self.type = 1
            <FONT COLOR=#3333CC><B>else</B></FONT>:
                self.message = <FONT COLOR=#115511>"&lt; "</FONT>+ self.username + <FONT COLOR=#115511>" has joined the chat.&gt;"</FONT>
                self.command = command
                self.type = 1
            <FONT COLOR=#3333CC><B>return</B></FONT> 1
        <FONT COLOR=#3333CC><B>elif</B></FONT> command == <FONT COLOR=#115511>"EMOTE"</FONT>:
            <FONT COLOR=#3333CC><B>if</B></FONT> length &gt;= 2:
                self.message = string.join(commandlist[1:],<FONT COLOR=#115511>" "</FONT>)
                self.command = command
                self.type = 1
                <FONT COLOR=#3333CC><B>return</B></FONT> 1
            <FONT COLOR=#3333CC><B>else</B></FONT>:
                <FONT COLOR=#3333CC><B>return</B></FONT> 0
        <FONT COLOR=#3333CC><B>else</B></FONT>:
            <FONT COLOR=#115511>"""
            There is a syntax error in the command so don't
            bother changing anything.  
            """</FONT>
        <FONT COLOR=#3333CC><B>return</B></FONT> 0
    
    <FONT COLOR=#115511>"""
    string = read_handle(self)
    
    Based upon message type this function is called to
    actually return the string representation of the
    command as a message object for printing.

    This is usually executed on the recieving client side.
    """</FONT>
    <FONT COLOR=#3333CC><B>def</B></FONT><A NAME="read_handle"><FONT COLOR=#CC0000><B> read_handle</B></FONT></A>(self):
        <FONT COLOR=#1111CC># Client Side Commands</FONT>
        <FONT COLOR=#3333CC><B>if</B></FONT> self.type == 1:
            <FONT COLOR=#3333CC><B>if</B></FONT> self.command == <FONT COLOR=#115511>"JOIN"</FONT>:
                string = self.message
            <FONT COLOR=#3333CC><B>elif</B></FONT> self.command == <FONT COLOR=#115511>"EMOTE"</FONT>:
                string = <FONT COLOR=#115511>"*** "</FONT> + self.username + <FONT COLOR=#115511>" "</FONT> + self.message + <FONT COLOR=#115511>" ***"</FONT>
            <FONT COLOR=#3333CC><B>else</B></FONT>: <FONT COLOR=#1111CC># Default Case</FONT>
                string = self.username+<FONT COLOR=#115511>": "</FONT> + self.message + \
                         <FONT COLOR=#115511>"( "</FONT>+ self.command + <FONT COLOR=#115511>" )"</FONT>
        <FONT COLOR=#1111CC># Basic Messages</FONT>
        <FONT COLOR=#3333CC><B>elif</B></FONT> self.type == 0:
            string = self.username + <FONT COLOR=#115511>"( "</FONT> + \
                     self.time + <FONT COLOR=#115511>" ): "</FONT> + self.message
        <FONT COLOR=#3333CC><B>else</B></FONT>:
            <FONT COLOR=#3333CC><B>return</B></FONT> <FONT COLOR=#115511>"Type 2 or 3 messages arriving on Clients are Bugs"</FONT>
        <FONT COLOR=#3333CC><B>return</B></FONT> string
    
    <FONT COLOR=#3333CC><B>def</B></FONT><A NAME="getCommand"><FONT COLOR=#CC0000><B> getCommand</B></FONT></A>(self):
        <FONT COLOR=#115511>"""
        Called by the Server if self.type == 1 or 2
        Returns a tuple of the Name of the Command,
        and the argument that command requires, if anything.
        Kick takes a username,
        Exit takes a message,
        Private takes a username, etc.
        """</FONT>
        cmd = self.command.split(<FONT COLOR=#115511>"&lt;"</FONT>)
        <FONT COLOR=#1111CC># cmd = ["ANY&gt;ANYTHING","/ANY&gt;"]</FONT>
        cmd = cmd[1].split(<FONT COLOR=#115511>"&gt;"</FONT>) <FONT COLOR=#1111CC># cmd[0]=="ANY&gt;ANYTHING"</FONT>
        <FONT COLOR=#1111CC># cmd = ["ANY","ANYTHING"]</FONT>
        <FONT COLOR=#3333CC><B>if</B></FONT> len(cmd) &gt; 1:
            <FONT COLOR=#3333CC><B>return</B></FONT> (cmd[0],cmd[1]) <FONT COLOR=#1111CC># ( Command Type, Value )</FONT>
        <FONT COLOR=#3333CC><B>else</B></FONT>:
            <FONT COLOR=#3333CC><B>return</B></FONT> (cmd[0],)

    <FONT COLOR=#3333CC><B>def</B></FONT><A NAME="str"><FONT COLOR=#CC0000><B> str</B></FONT></A>(self):
        string = self.read_handle()
        <FONT COLOR=#3333CC><B>return</B></FONT> string

    <FONT COLOR=#3333CC><B>def</B></FONT><A NAME="__repr__"><FONT COLOR=#CC0000><B> __repr__</B></FONT></A>(self):
        <FONT COLOR=#3333CC><B>return</B></FONT> self.str()

    <FONT COLOR=#3333CC><B>def</B></FONT><A NAME="__str__"><FONT COLOR=#CC0000><B> __str__</B></FONT></A>(self):
        <FONT COLOR=#3333CC><B>return</B></FONT> self.str()

<FONT COLOR=#3333CC><B>def</B></FONT><A NAME="ConnectRead"><FONT COLOR=#CC0000><B> ConnectRead</B></FONT></A>( username ):
    connect = Message(username,<FONT COLOR=#115511>"Connecting Client Read Thread"</FONT>,
                                   <FONT COLOR=#115511>"&lt;_READ_&gt;"</FONT>,None)
    connect.type = 2
    <FONT COLOR=#3333CC><B>return</B></FONT> connect

<FONT COLOR=#3333CC><B>def</B></FONT><A NAME="ConnectWrite"><FONT COLOR=#CC0000><B> ConnectWrite</B></FONT></A>( username ):
    connect = Message(username,<FONT COLOR=#115511>"Connecting Client Write Thread"</FONT>,
                                   <FONT COLOR=#115511>"&lt;_WRITE_&gt;"</FONT>,None)
    connect.type = 2
    <FONT COLOR=#3333CC><B>return</B></FONT> connect

<FONT COLOR=#1111CC># This command needs to be replaced with more robust</FONT>
<FONT COLOR=#1111CC># calls that actually do the work of determining</FONT>
<FONT COLOR=#1111CC># what the command is, or whether a plaintext string is a command.</FONT>
<FONT COLOR=#3333CC><B>def</B></FONT><A NAME="splitCommand"><FONT COLOR=#CC0000><B> splitCommand</B></FONT></A>(command):
    <FONT COLOR=#115511>"""
    Called by the Server if self.type == 1 or 2
    Returns a tuple of the Name of the Command,
    and the argument that command requires, if anything.
    Kick takes a username,
    Exit takes a message,
    Private takes a username, etc.
    """</FONT>
    cmd = command.split(<FONT COLOR=#115511>"&lt;"</FONT>)
    <FONT COLOR=#1111CC># cmd = ["ANY&gt;ANYTHING","/ANY&gt;"]</FONT>
    cmd = cmd[1].split(<FONT COLOR=#115511>"&gt;"</FONT>) <FONT COLOR=#1111CC># cmd[0]=="ANY&gt;ANYTHING"</FONT>
    <FONT COLOR=#1111CC># cmd = ["ANY","ANYTHING"]</FONT>
    <FONT COLOR=#3333CC><B>if</B></FONT> len(cmd) &gt; 1:
        <FONT COLOR=#3333CC><B>return</B></FONT> (cmd[0],cmd[1]) <FONT COLOR=#1111CC># ( Command Type, Value )</FONT>
    <FONT COLOR=#3333CC><B>else</B></FONT>:
            <FONT COLOR=#3333CC><B>return</B></FONT> (cmd[0],)

    
</PRE>
                  <!--footer-->
                  </BODY>
